package net.pulseproject.commons.midi.mediator;

import javax.sound.midi.MidiMessage;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;

import net.pulseproject.commons.midi.MessageAnalyzer;
import net.pulseproject.commons.midi.Transmitable;
import net.pulseproject.commons.midi.entity.MidiSocket;
import net.pulseproject.commons.util.MidiUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MidiReceiver implements Receiver {

	private static final Log LOG = LogFactory.getLog(MidiReceiver.class);
	
	private final MessageAnalyzer analyzer;
	
	private final String transmitterPort;
	
	private final Transmitable midiTransmitableWrapper;
	
	private final MidiReceiverListener listener;
	
	
	public MidiReceiver(final MessageAnalyzer analyzer, final String transmitterPort,
			final MidiReceiverListener listener) {
		LOG.debug("new MidiReceiver(analyzer, transmitterPort=[" + transmitterPort + "], listener)");
		if(analyzer == null) { throw new IllegalArgumentException("analyzer == null"); }
		this.analyzer = analyzer;
		
		if(transmitterPort == null) { throw new IllegalArgumentException("transmitterPort == null"); }
		if(transmitterPort.isEmpty()) { throw new IllegalArgumentException("transmitterPort is empty"); }
		this.transmitterPort = transmitterPort;
		this.midiTransmitableWrapper = new MidiTransmitterTransmitableWrapper(transmitterPort);
		
		if(listener == null) { throw new IllegalArgumentException("listener == null"); }
		this.listener = listener;
	}
	
	/**
	 * Will be invoked by mmj's own thread.
	 */
	@Override
	public final void send(final MidiMessage message, final long timeStamp) {
		try {
			final ShortMessage shortMessage = (ShortMessage) message;
			LOG.debug("send(message=" + MidiUtil.toString(shortMessage) + ", timeStamp) ... " +
					"this.transmitterPort=[" + this.transmitterPort + "]");
			
			final MidiSocket socket = this.analyzer.createMidiSocket(shortMessage, this.transmitterPort);
			
			// listener is most likely MediatorImpl
			this.listener.onMidiReceived(shortMessage, this.midiTransmitableWrapper, socket);
			
		} catch(final Exception e) {
			// TODO actually would like to display JOptionPane directly here, but better would be
			//      to dispatch an event indicating something went wrong
			LOG.error("Exception while dispatching MIDI message!", e);
		}
	}

	@Override
	public final void close() {
		LOG.info("close()");
	}

}
